#ifndef xpack_lang_cxx_encode_item_as
#define xpack_lang_cxx_encode_item_as
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::lang_cxx::inc
#include"configure/limit.hpp"
#include"define/base_type.hpp"
#include"lang/cxx/encode_first_as.hpp"
#include"lang/cxx/length_if_item_as.hpp"
#include"lang/cxx.hpp"
#include"lang/wxx/length_if_as_utf8.hpp"
#include"macro/xunlikely.hpp"
#include"memop/copy.hpp"
#include"meta/unsigned_type.hpp"
#include"meta/is_same.hpp"
#pragma pop_macro("xuser")

namespace mixc::lang_cxx{
    template<class item_t, class char_t>
    struct saturate_wrap{
        void operator=(item_t value){
            // 窄化时作饱和运算
            if constexpr (sizeof(char_t) < sizeof(item_t)){
                auto max_value_of_item = (1 << (sizeof(char_t) * 8)) - 1;
                item = value > max_value_of_item ? char_t(-1) : value;
            }
            else{
                item = value;
            }
        }

        char_t item;
    };

    template<class item_t>
    template<inc::is_base_char char_t>
    inline cxx<char_t> cxx<item_t>::encode_item_as(allocx_t<char_t> alloc) const {
        using saturate_wrapp = saturate_wrap<item_t, char_t> *;

        // 若是同类型串或者都是宽字符串
        if constexpr (
            (inc::is_same<char_t, item_t>) or
            (sizeof(item_t) >= 2 and sizeof(char_t) >= 2)
        ){
            auto length = uxx(xthe->length);
            auto target = alloc(length);

            xunlikely(target == nullptr){
                return {};
            }
            else{
                inc::copy_with_operator_unsafe(saturate_wrapp(target), (item_t *)xthe, length);
                return { target, length };
            }
        }

        // 多字节串、宽字符串互转
        else{
            auto source = xthe;
            auto source_length = uxx(xthe->length);
            auto target_length = xthe.template length_if_item_as<char_t>();
            auto target = alloc(target_length);
            auto ptr = target;

            xunlikely(target == nullptr){
                return {};
            }

            for(uxx i = 0; i < source_length;){
                auto sequence = source.template encode_first_as<char_t>();
                inc::copy_with_operator_unsafe(ptr, sequence.ptr(), sequence->length);
                source = source.backward(sequence->length);
                i += sequence->skip_to_next;
                ptr += sequence->length;
            }
            
            return { target, target_length };
        }
    }

    template<class item_t>
    template<inc::is_base_char char_t>
    inline void cxx<item_t>::encode_item_as(streamx_t<char_t> stream) const {
        // 若是同类型串或者都是宽字符串
        if constexpr (
            (inc::is_same<char_t, item_t>) or
            (sizeof(item_t) >= 2 and sizeof(char_t) >= 2)
        ){
            auto self   = xthe;
            auto length = uxx(self->length);

            if (stream != nullptr){
                saturate_wrap<item_t, char_t> temp[inc::limit::lang_cxx_encode_item_as];
                for(uxx c = length; c != 0;){
                    uxx count   = inc::minimum<uxx>(c, inc::limit::lang_cxx_encode_item_as);
                    inc::copy_with_operator_unsafe(temp, (item_t *)self, length);
                    stream.output(temp, count);

                    c          -= count;
                    self        = self.backward(count);
                }
            }
        }

        // 多字节串、宽字符串互转
        else{
            auto source = xthe;
            auto source_length = uxx(xthe->length);

            if (stream != nullptr){
                char_t temp[inc::limit::lang_cxx_encode_item_as];
                char_t * ptr = temp;
                char_t * end = ptr + inc::limit::lang_cxx_encode_item_as;

                for(uxx i = 0; i < source_length;){
                    auto sequence = source.template encode_first_as<char_t>();

                    if (ptr + sequence->length > end){
                        stream.output(temp, ptr - temp);
                        ptr = temp;
                    }

                    inc::copy_with_operator_unsafe(ptr, sequence.ptr(), sequence->length);
                    source = source.backward(sequence->length);
                    i += sequence->skip_to_next;
                    ptr += sequence->length;
                }

                if (ptr != temp){
                    stream.output(temp, ptr - temp);
                }
            }
        }
    }
}

#endif
